// Copyright (c) 2006 Zorm
// Released under the MIT License

#include "PCH.h"
#include "..\Common.h"

bool MainWindow::CreateWindows() {

	INITCOMMONCONTROLSEX cc;
	cc.dwSize = sizeof(INITCOMMONCONTROLSEX);
	cc.dwICC = ICC_BAR_CLASSES | ICC_TAB_CLASSES;

	if (!InitCommonControlsEx(&cc)) {
		return false;
	}

	if (!(m_richEditDLL = LoadLibrary(TEXT("RichEd32.dll")))) {
		return false;
	}

	if (!RegisterClass()) {
		return false;
	}

	if (!CreateWindowEx(WS_EX_APPWINDOW | WS_EX_OVERLAPPEDWINDOW, ClassName(), WindowName(), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT , CW_USEDEFAULT, NULL, NULL, m_pgmInstance, this)) {
		return false;
	}

	return true;
}

LRESULT MainWindow::HandleMessage(UINT message, WPARAM wParam, LPARAM lParam) {
	switch (message) {
		case WM_COMMAND: {
			switch (LOWORD(wParam)) {
				case MENU_ABOUT: {
					AboutDialog *About;
					About = new AboutDialog(m_pgmInstance, DIALOG_ABOUT);
					About->MakeDialog(m_windowHWND);
					return 0;
				}
				case MENU_SELECT: {
					SelectDialog *Select;
					Select = new SelectDialog(m_pgmInstance, DIALOG_SELECT);
					Select->MakeDialog(m_windowHWND);
					return 0;
				}
				case MENU_EXIT: {
					ExitProcess(0);
					return 0;
				}
			}
			return 0;
		}
		case WM_CREATE: {
			m_statusHWND = CreateWindowEx(NULL, STATUSCLASSNAME, TEXT(""), SBARS_SIZEGRIP | WS_CHILD | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT , CW_USEDEFAULT, m_windowHWND, NULL, m_pgmInstance, NULL);
			int widths[2] = {150, -1};
			
			SendMessage(m_statusHWND, SB_SETPARTS, 2, (LPARAM)widths);
			
			TCITEM tie;
			tie.pszText = TEXT("System");
			tie.mask = TCIF_TEXT;
			
			m_tabHWND = CreateWindowEx(NULL, WC_TABCONTROL, TEXT(""), WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | TCS_BUTTONS | TCS_FLATBUTTONS | TCS_FOCUSNEVER, 0, 40, 200, 20, m_windowHWND, NULL, m_pgmInstance, NULL);
			TabCtrl_InsertItem(m_tabHWND, 0, &tie);
			m_activeTab = 0;

			m_staticHWND = CreateWindowEx(0, TEXT("STATIC"), TEXT(""), WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | SS_NOTIFY, 20, 20, 290, 120, m_windowHWND, NULL, m_pgmInstance, NULL);
			SetWindowLongPtr(m_staticHWND, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
			m_staticProc = (WNDPROC)(LONG_PTR)SetWindowLongPtr(m_staticHWND, GWL_WNDPROC, (LONG)(LONG_PTR)StaticSubclassStatic);
			
			m_richEditHWND = CreateWindowEx(0, RICHEDIT_CLASS, TEXT(""), WS_CHILD | WS_VSCROLL | WS_VISIBLE | ES_AUTOVSCROLL | ES_MULTILINE | ES_NOHIDESEL | ES_READONLY, 20, 20, 290, 120, m_windowHWND, NULL, m_pgmInstance, NULL);
			SendMessage(m_richEditHWND, EM_AUTOURLDETECT, TRUE, 0);
			SendMessage(m_richEditHWND, EM_SETEVENTMASK, 0, ENM_LINK);
			SendMessage(m_richEditHWND, EM_SETBKGNDCOLOR, FALSE, 0);

			m_cfFormat.cbSize = sizeof(CHARFORMAT);
			m_cfFormat.dwMask = CFM_COLOR | CFM_FACE | CFM_SIZE | CFM_BOLD;
			m_cfFormat.dwEffects = CFE_PROTECTED;
			m_cfFormat.yHeight = 190;
			m_cfFormat.yOffset = 0;
			m_cfFormat.bCharSet = DEFAULT_CHARSET;
			m_cfFormat.bPitchAndFamily = DEFAULT_PITCH;
			_tcsncpy_s(m_cfFormat.szFaceName, 32, ATH::Instance()->GetConfig()->GetString(TEXT("system.font")).c_str(), _TRUNCATE);
			m_cfFormat.szFaceName[31] = 0;

			m_menuBar = CreateMenu();
			m_fileMenu = CreatePopupMenu();
			
			#define ADDMENUCHILD(a, b, c, d) AppendMenu(a, b, (UINT_PTR)c, d);
			#define ADDMENU(a, b, c, d) AppendMenu(a, b, MENU_##c, d);
			#include "menus.tbl"
			#undef ADDMENU
			#undef ADDMENUCHILD
			
			SetMenu(m_windowHWND, m_menuBar);
			DrawMenuBar(m_windowHWND);
			
			AddTab(TEXT("Norman Radar 1"));
			
			DragAcceptFiles(m_windowHWND, true);

			return 0;
		}
		case WM_DROPFILES: {
			int totalFiles = DragQueryFile((HDROP)wParam, 0xFFFFFFFF, NULL, NULL);
			for (int i = 0; i < totalFiles; i++) {
				TCHAR *buf;
				int buflen = DragQueryFile((HDROP)wParam, i, NULL, NULL) + 1;
				buf = new TCHAR[buflen];
				ZeroMemory(buf, buflen);
				DragQueryFile((HDROP)wParam, i, buf, buflen);
				ATH::Instance()->GetLog()->LogEvent(Log::LOG_INFO, TEXT("%i %s\n"), i, buf);
				//NIDSParser *parser = new NIDSParser(buf);
				//NIDSProductDescription productDesc = parser->GetProductDescription();
				//ATH::Instance()->GetLog()->LogEvent(Log::LOG_INFO, TEXT("%f %f\n"), productDesc.latitude, productDesc.longitude);
				//delete parser;
				delete [] buf;
			}
			DragFinish((HDROP)wParam);
			return 0;
		}
		case WM_DESTROY: {
			PostQuitMessage(0);
			return 0;
		}
		//case WM_ERASEBKGND: {
		//	return 1;
		//}
		case WM_KEYDOWN: {
			POINT pt;
			if (m_activeTab == 0) {
				return 0;
			}
			if ((GetKeyState(VK_CONTROL) & 0x8000) && wParam != VK_CONTROL) {
				ATH::Instance()->GetLog()->LogEvent(Log::LOG_INFO, TEXT("keydown %c\n"), wParam);
				switch (wParam) {
					case VK_UP:
						GetCursorPos(&pt);
						ScreenToClient(m_staticHWND, &pt);
						ATH::Instance()->GetRadarInfo()->IncreaseScale(1);
						ATH::Instance()->GetRadarInfo()->FocusMap(pt.x, pt.y);
						RedrawRadar();
						break;
					case VK_DOWN:
						GetCursorPos(&pt);
						ScreenToClient(m_staticHWND, &pt);
						ATH::Instance()->GetRadarInfo()->DecreaseScale(1);
						ATH::Instance()->GetRadarInfo()->FocusMap(pt.x, pt.y);
						RedrawRadar();
						break;
				}
			}
			return 0;
		}
		case WM_NOTIFY: {
			NMHDR *hdr = (LPNMHDR)lParam;
			switch (hdr->code) {
				case TCN_SELCHANGE: { 
					int iPage = TabCtrl_GetCurSel(m_tabHWND);
					if (iPage == 0) {
						m_activeTab = 0;
						SetLatLon();
						ShowWindow(m_richEditHWND, SW_SHOW);
						ShowWindow(m_staticHWND, SW_HIDE);
					} else {
						ATH::Instance()->GetRadarManager()->SwitchToRadar(iPage);
						if (!m_activeTab) {
							m_activeTab = 1;
							ShowWindow(m_staticHWND, SW_SHOW);
							ShowWindow(m_richEditHWND, SW_HIDE);
							SetFocus(m_staticHWND);
						}
					}
					return 0;
				}
			}
			return 0;
		}
		case WM_SETFOCUS: {
			if (m_activeTab == 1) {
				SetFocus(m_staticHWND);
			}
			return 0;
		}
		case WM_SIZE: {
			if (wParam != SIZE_MINIMIZED) {
				SendMessage(m_statusHWND, WM_SIZE, wParam, lParam);
				SetWindowPos(m_tabHWND, NULL, 0, 20, LOWORD(lParam), 25, SWP_NOACTIVATE | SWP_NOZORDER);
				SetWindowPos(m_richEditHWND, NULL, 0, 45, LOWORD(lParam), HIWORD(lParam) - 45 - 20, SWP_NOACTIVATE | SWP_NOZORDER);
				SetWindowPos(m_staticHWND, NULL, 0, 45, LOWORD(lParam), HIWORD(lParam) - 45 - 20, SWP_NOACTIVATE | SWP_NOZORDER);
				SendMessage(m_richEditHWND, WM_VSCROLL, SB_BOTTOM, 0);
			}
			return 0;
		}
		default: {
			return DefWindowProc(m_windowHWND, message, wParam, lParam);
		}
	}
}

int MainWindow::AddTab(TCHAR *text) {
	TCITEM tie;
	tie.pszText = text;
	tie.mask = TCIF_TEXT;
	tie.iImage = -1;
	return TabCtrl_InsertItem(m_tabHWND, m_tabCount++, &tie);
}

void MainWindow::Update() {
	RECT r = {0};
	GetClientRect(m_staticHWND, &r);
	ATH::Instance()->GetGLContext()->Resize(r.right, r.bottom);
}

void MainWindow::AddText(TCHAR *format, ...) {
	LONG linecount = 0, linecount2 = 0;
	SCROLLINFO SI;
	POINT p;
	CHARRANGE Range = {-1, -1}, Range2 = {-1, -1}, Range3 = {-1, -1};
	EDITSTREAM editStream;
	va_list vaArg;
	va_start(vaArg, format);
	_vsntprintf_s(m_txtToAppend, _countof(m_txtToAppend), _TRUNCATE, format, vaArg);
	va_end(vaArg);
	m_textToAppendSize = _tcslen(m_txtToAppend) * sizeof(TCHAR);
	ZeroMemory(&SI, sizeof(SI));
	SI.cbSize = sizeof(SI);
	SI.fMask = 7;

	m_cfFormat.crTextColor = m_cColor;
	if (m_activeTab == 0) {
		SendMessage(m_richEditHWND, WM_SETREDRAW, 0, 0);
	}
	SendMessage(m_richEditHWND, EM_GETSCROLLPOS, 0, (LPARAM)&p);
	GetScrollInfo(m_richEditHWND, SB_VERT, &SI);
	linecount = (LONG)SendMessage(m_richEditHWND, EM_GETLINECOUNT, 0, 0);
	SendMessage(m_richEditHWND, EM_EXGETSEL, 0, (LPARAM)&Range);
	SendMessage(m_richEditHWND, EM_EXSETSEL, 0, (LPARAM)&Range2);
	SendMessage(m_richEditHWND, EM_EXGETSEL, 0, (LPARAM)&Range3);
	SendMessage(m_richEditHWND, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&m_cfFormat);
	editStream.dwCookie = (DWORD_PTR)this;
	editStream.dwError = 0;
	editStream.pfnCallback = EditStreamCallback;
	SendMessage(m_richEditHWND, EM_STREAMIN, SF_TEXT | SFF_SELECTION | STREAMFLAGS, (LPARAM)&editStream);
	linecount2 = (LONG)SendMessage(m_richEditHWND, EM_GETLINECOUNT, 0, 0);
	if (linecount2 > 2000) {
		Range2.cpMin = 0;
		Range2.cpMax = (LONG)SendMessage(m_richEditHWND, EM_LINEINDEX, 1, 0);
		SendMessage(m_richEditHWND, EM_EXSETSEL, 0, (LPARAM)&Range2);
		SendMessage(m_richEditHWND, EM_REPLACESEL, 0, (LPARAM)TEXT(""));
		Range.cpMin -= Range2.cpMax;
		Range.cpMax -= Range2.cpMax;
	}
	SendMessage(m_richEditHWND, EM_EXSETSEL, 0, (LPARAM)&Range);
	SendMessage(m_richEditHWND, EM_SETSCROLLPOS, 0, (LPARAM)&p);

	if(linecount == 1 || SI.nMax == SI.nPos + (int)SI.nPage) {
		SendMessage(m_richEditHWND, WM_VSCROLL, SB_BOTTOM, 0);
	} else if (linecount2 > 2000) {
		SendMessage(m_richEditHWND, EM_LINESCROLL, 0, -1);
	}
	if (m_activeTab == 0) {
		SendMessage(m_richEditHWND, WM_SETREDRAW, 1, 0);
		InvalidateRect(m_richEditHWND, 0, 1);
	}
}

void MainWindow::SetColor(COLORREF color) {
	m_cColor = m_colors[color];
}

void MainWindow::TimeStamp() {
	SYSTEMTIME st;
	GetLocalTime(&st);
	SetColor(MainWindow::CWHITE);
	AddText(TEXT("[%02i:%02i:%02i] "), st.wHour, st.wMinute, st.wSecond);
}

void MainWindow::LoadColors() {
	m_colors[MainWindow::CWHITE] = 0xFFFFFF;
	m_colors[MainWindow::CBLUE] = 7556390;
	m_colors[MainWindow::CBLUEGREEN] = 7566118;
	m_colors[MainWindow::CDARKBLUE] = 7546406;
	m_colors[MainWindow::CDARKGREEN] = 2519846;
	m_colors[MainWindow::CDARKPURPLE] = 7546445;
	m_colors[MainWindow::CDARKRED] = 5056115;
	m_colors[MainWindow::CDARKYELLOW] = 2510195;
	m_colors[MainWindow::CGREEN] = 5075750;
	m_colors[MainWindow::CGREY] = ATH::Instance()->GetConfig()->GetDWORD(TEXT("system.color1"));//12632256;
	m_colors[MainWindow::CLIGHTBLUE] = 12880463;
	m_colors[MainWindow::CMIDBLUE] = 10578742;
	m_colors[MainWindow::CPURPLE] = 7546483;
	m_colors[MainWindow::CRED] = 2500211;
	m_colors[MainWindow::CYELLOW] = 2519923;
}

LRESULT CALLBACK MainWindow::StaticSubclass(UINT msg, WPARAM wParam, LPARAM lParam) {
	switch (msg) {
		case WM_KEYDOWN: {
			if (GetKeyState(VK_CONTROL) & 0x8000) {
				ATH::Instance()->GetLog()->LogEvent(Log::LOG_INFO, TEXT("keydown %c\n"), wParam);
				switch (wParam) {
					case VK_UP:
						ATH::Instance()->GetRadarInfo()->DecreaseScale(1);
						ATH::Instance()->GetRadarInfo()->FocusMap((int)ATH::Instance()->GetGLContext()->GetCenterX(), (int)ATH::Instance()->GetGLContext()->GetCenterY());
						RedrawRadar();
						break;
					case VK_DOWN:
						ATH::Instance()->GetRadarInfo()->DecreaseScale(1);
						ATH::Instance()->GetRadarInfo()->FocusMap((int)ATH::Instance()->GetGLContext()->GetCenterX(), (int)ATH::Instance()->GetGLContext()->GetCenterY());
						RedrawRadar();
						break;
				}
			}
			return 0;
		}
		case WM_ERASEBKGND: {
			return 1;
		}
		case WM_LBUTTONUP: {
			ATH::Instance()->GetGLContext()->CaptureScreen("test.png");
			return 0;
		}
		case WM_MOUSEMOVE: {
			double xOffset = 0, yOffset = 0;
			short x = 0, y = 0;
			x = LOWORD(lParam);
			y = HIWORD(lParam);
			/*double px = x - ATH::Instance()->GetGLContext()->GetCenterX();
			px = px * (1/ATH::Instance()->GetRadarInfo()->GetScale()) - ATH::Instance()->GetRadarInfo()->GetFocusX();
			px /= 100000.0;
			px = ATH::Instance()->GetRadarInfo()->GetLongitude() + px;
			
			double py = y - ATH::Instance()->GetGLContext()->GetCenterY();
			py = py * (1/ATH::Instance()->GetRadarInfo()->GetScale()) + ATH::Instance()->GetRadarInfo()->GetFocusY();
			py /= 100000.0;
			py = ATH::Instance()->GetRadarInfo()->GetLatitude() - py;*/
			double lat = 0, lon = 0;
			ATH::Instance()->GetGLContext()->Unproject(x, y, &lat, &lon);
			SetLatLon(lat, lon);
			return 0;
			//ATH::Instance()->GetLog()->LogEvent(Log::LOG_INFO, TEXT("mouse up %i, %i %f %f\n"), x, y, py, px);
		}
		case WM_PAINT: {
			PAINTSTRUCT ps;
			BeginPaint(m_staticHWND, &ps);
			if (ATH::Instance()->GetGLContext()) {
				glClear(GL_COLOR_BUFFER_BIT);
				ATH::Instance()->GetGLContext()->Draw();
				ATH::Instance()->GetGLContext()->Swap();
			}
			EndPaint(m_staticHWND, &ps);
			return 0;
		}
		case WM_MOUSEWHEEL: {
			short delta = short(HIWORD(wParam)) / 120;
			POINT mouse = {0};
			GetCursorPos(&mouse);
			ScreenToClient(m_staticHWND, &mouse);
			if (delta >= 0) {
				ATH::Instance()->GetRadarInfo()->IncreaseScale(delta);
				ATH::Instance()->GetRadarInfo()->FocusMap(mouse.x, mouse.y);
				RedrawRadar();
			} else if (delta < 0) {
				ATH::Instance()->GetRadarInfo()->DecreaseScale(-delta);
				ATH::Instance()->GetRadarInfo()->FocusMap(mouse.x, mouse.y);
				RedrawRadar();
			}
			return 0;
		}
		case WM_SIZE: {
			if (ATH::Instance()->GetGLContext()) {
				ATH::Instance()->GetGLContext()->Resize(LOWORD(lParam), HIWORD(lParam));
			}
			return 0;
		}
		default: {
			return CallWindowProc(m_staticProc, m_staticHWND, msg, wParam, lParam);
		}
	}
}

void MainWindow::SetLatLon(double lat, double lon) {
	TCHAR buf[128] = TEXT("");
	_sntprintf_s(buf, 128, _TRUNCATE, TEXT("%.05f, %.05f"), lat, lon);
	buf[127] = 0;
	SendMessage(m_statusHWND, SB_SETTEXT, 0, (LPARAM)buf);
}

void MainWindow::SetLatLon() {
	SendMessage(m_statusHWND, SB_SETTEXT, 0, (LPARAM)0);
}

DWORD MainWindow::EditCallback(LPBYTE pbBuff, LONG cb, LONG *pcb) {
	*pcb = cb;
	if (*pcb > (LONG)m_textToAppendSize) {
		*pcb = (LONG)m_textToAppendSize;
	}
	if (*pcb > 0) {
		memcpy(pbBuff, m_txtToAppend, *pcb);
		m_textToAppendSize -= *pcb;
	}
	return 0;
}

DWORD CALLBACK MainWindow::EditStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb) {
	MainWindow *self = NULL;
	self = reinterpret_cast<MainWindow *>(dwCookie);
	if (self) {
		return self->EditCallback(pbBuff, cb, pcb);
	} else {
		return 0;
	}
}

LRESULT CALLBACK MainWindow::StaticSubclassStatic(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
	MainWindow *self;
	self = reinterpret_cast<MainWindow *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
	return self->StaticSubclass(msg, wParam, lParam);
}